/*****************************************************************************************/
/* Filename : SenseToRadioC.nc                                                           */
/*****************************************************************************************/
/*                                                                                       */
/* This code is intended for the EasySen SBT80 Sensor board along with TelosB            */
/* family of wireless motes. It samples the 8 sensor channels in the following order:    */
/* Visual Light (VL), Microphone (MIC), Infrared (IR), Temperature (TEMP),               */ 
/* Acceleration over x axis (ACCx), Acceleration over y axis (ACCy),                     */
/* Magnetic field over x axis (MGx), Magnetic field over y axis (MGy).                   */
/* Sampling is performed over each ADC channel individually.                             */
/*                                                                                       */
/* For further details, please refer to README.txt and                                   */ 
/* Guide_to_TinyOS20_code_for_EasySen_SensorBoards.doc                                   */
/*                                                                                       */
/* Disclaimer: Easysen does not take on any liability for the use of this code.          */
/* This code is not designed for use in critical or life support systems                 */
/* where failure to perform affects safety or effectiveness or results in                */
/* any personal injury to the user. This code is available for free downloading          */
/* at www.easysen.com, and not for sale.                                                 */ 
/*                                                                                       */
/*****************************************************************************************/


#include "Timer.h"
#include "SenseToRadio.h"
#include "SBT80ADCmap.h"
#include "printf.h"

module SenseToRadioC
{
  uses {
    interface Boot;
    interface Leds;
    interface Timer<TMilli> as WakeupTimer;

    interface Read<uint16_t> as ReadTEMP;
    interface Read<uint16_t> as ReadACCMGx;
    interface Read<uint16_t> as ReadACCMGy;


    interface HplMsp430GeneralIO as SBcontrol;
    interface HplMsp430GeneralIO as SBswitch;

    interface Packet;
    interface AMPacket;
    interface AMSend;
    interface SplitControl as AMControl;
  }
}


implementation
{
  /* Define variables and constants */  

  #define SAMPLING_FREQUENCY 100  /* should be higher than 100 ms */

  uint16_t ChannelNo = 0; 
  uint16_t counter   = 0;

  /* global variables to hold sensor readings */ 
  uint16_t TEMPdata, ACCxdata, ACCydata;

  uint8_t len;
  bool busy = FALSE;  /* used to keep track if radio is busy */
  bool is_in_trauma = FALSE;  /* used to indicate if a tramatic hit occured */

  message_t reading_packet, trauma_packet;
  void task getData();
  
  /* Initializations at powerup */  
  event void Boot.booted()
  {
    call Leds.led0Off();
    call WakeupTimer.startPeriodic(SAMPLING_FREQUENCY);
    call AMControl.start();

    /* Wake up the sensor board */
    call SBcontrol.clr();
    call SBcontrol.makeOutput();
    call SBcontrol.selectIOFunc();

    /* set to read the accel */
    call SBswitch.clr();  // Low = Acceleration
    call SBswitch.makeOutput();
    call SBswitch.selectIOFunc();		
  }

  /**
   * Start reading event handlers
   */
  event void WakeupTimer.fired() {
    
    ChannelNo = 0;
    post getData();

    counter++;
    printf("Wakeup Counter: %u \n", counter);
  }

  void task getData() {
    call ReadTEMP.read();
  }

  /**
   * Radio Send Event Handlers
   */
  event void AMControl.startDone(error_t err) { }
  event void AMControl.stopDone(error_t err) { }
  event void AMSend.sendDone(message_t* msg, error_t error) {
    if (&reading_packet == msg) {
      /* reset the current values */
      SenseToRadioMsg* ptr_packet = (SenseToRadioMsg*)(call Packet.getPayload(&reading_packet, len));
      ptr_packet->data[0] = 0x00;
      ptr_packet->data[1] = 0x00;
      ptr_packet->data[2] = 0x00;

      /* reset the status */
      busy = FALSE;
      call Leds.led2Off();
      printf("Wakeup Counter after packet Tx: %u \n", counter);
      printf("Sensor readings       :    TEMP  ACCx  ACCy\n");
      printf("range 0-4095 (decimal):  %4u  %4u  %4u\n\n", TEMPdata, ACCxdata, ACCydata);
    }
  }

  /* -------- EVENT: TEMP channel sampling done - Read Acceleration channel X --------------- */
  event void ReadTEMP.readDone(error_t result, uint16_t data) { 
    SenseToRadioMsg* ptr_packet = (SenseToRadioMsg*)(call Packet.getPayload(&reading_packet, len));
    ptr_packet->data[ChannelNo++] = data;

    TEMPdata = data;
    call ReadACCMGx.read();
  }


  /* -------- EVENT: Acceleration or Magnetic chanel X sampling done --------------- */
  event void ReadACCMGx.readDone(error_t result, uint16_t data) { 
    SenseToRadioMsg* ptr_packet = (SenseToRadioMsg*)(call Packet.getPayload(&reading_packet, len));
    ptr_packet->data[ChannelNo++] += data;

    is_in_trauma |= (data > 3000);
    ACCxdata = data;
    call ReadACCMGy.read();
  }

  /* -------- EVENT: Acceleration or Magnetic chanel Y data ready --------------- */
  event void ReadACCMGy.readDone(error_t result, uint16_t data) { 
    SenseToRadioMsg* ptr_packet = (SenseToRadioMsg*)(call Packet.getPayload(&reading_packet, len));
    ptr_packet->data[ChannelNo++] += data;

    is_in_trauma |= (data > 3000);
    ACCydata = data;
    
    if (!busy && is_in_trauma) {
      SenseToRadioTraumaMsg* ptt_packet = (SenseToRadioTraumaMsg*)(call Packet.getPayload(&trauma_packet, len));
      ptt_packet->data[0] = ACCxdata;
      ptt_packet->data[1] = ACCydata;
      
      if (call AMSend.send(AM_BROADCAST_ADDR, &trauma_packet, sizeof(SenseToRadioTraumaMsg)) == SUCCESS) {
        call Leds.led2On();
        busy = TRUE;
        is_in_trauma = FALSE;
      }
    }

    if (!busy && ((counter % 50) == 0)) {
      if (call AMSend.send(AM_BROADCAST_ADDR, &reading_packet, sizeof(SenseToRadioMsg)) == SUCCESS) {
        call Leds.led2On();
        busy = TRUE;
      }
    }
  }
}

